using System;
using UnityEngine;

namespace EventBehaviorTree
{
    [Serializable]
    public class SimpleRepeater : Container<ContainerMode>
    {
        private int _repeatCount;
        private int _repeatLimit;
        private int RepeatCount { get => _repeatCount; set => _repeatCount = Math.Max(0, value); }
        private int RepeatLimit { get => _repeatLimit; set => _repeatLimit = Math.Max(0, value); }

        private int _attemptCount;
        private int _attemptLimit;
        private int AttemptCount { get => _attemptCount; set => _attemptCount = Math.Max(0, value); }
        private int AttemptLimit { get => _attemptLimit; set => _attemptLimit = Math.Max(-1, value); }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="workMode"></param>
        /// <param name="isStopInstantly"></param>
        /// <param name="isStopSimultaneously"></param>
        /// <param name="attemptLimit">When failed, the node will restart automatically.-1 means always restart, 0 means never restart</param>
        /// <param name="repeatLimit">Repeat 0 times means repeat forever</param>
        public SimpleRepeater(string workMode = "Async", int attemptLimit = 0, int repeatLimit = 0)
        {
            AttemptLimit = attemptLimit;
            AttemptCount = 0;
            RepeatLimit = repeatLimit;
            _workMode = (ContainerMode)Enum.Parse(typeof(ContainerMode), workMode);
            Condition = () => RepeatCount != 0 && RepeatLimit == RepeatCount;//get the goal
        }

        public override void NodeEvent(NodeMessage nodeMessage)
        {
            switch (nodeMessage)
            {
                case NodeMessage.Start:
                    _stepCount = 0;
                    ResetWorker();
                    _coroutineStarter.StartCoroutine(_worker);
                    _subNodes[0].NodeEvent(NodeMessage.Start);
                    return;
                case NodeMessage.Success:
                    if (_stepCount < _subNodes.Count - 1)
                    {
                        _subNodes[++_stepCount].NodeEvent(NodeMessage.Start);
                        return;
                    }
                    //the last sub node will do this: all successed
                    AttemptCount = 0;//attempt successed when the whole process done
                    if (++RepeatCount < RepeatLimit) NodeEvent(NodeMessage.Start);//repeat with repeating count
                    else RepeatCount = 0;//refresh or when RepeatTimes = 0, repeat forever
                    return;
                case NodeMessage.Failure:
                    if (AttemptLimit == -1 || ++AttemptCount <= AttemptLimit)//restart forever or haven't got the limit
                    {
                        if (AttemptLimit == -1) AttemptCount = 0;//restart forever
                        StopAllSubNodes();//forcly stop all sub nodes
                        _subNodes[0].NodeEvent(NodeMessage.Start);//restart with repeat counter saved
                        return;
                    }
                    RepeatCount = 0;
                    ResetWorker();
                    StopAllSubNodes();
                    SeniorNodeEvent(NodeMessage.Failure);
                    return;
                case NodeMessage.COMMAND_Stop:
                    RepeatCount = 0;
                    ResetWorker();
                    StopAllSubNodes();
                    return;
                case NodeMessage.REQUEST_Abort://abort[CONSIDER]
                    RepeatCount = 0;
                    ResetWorker();
                    StopAllSubNodes();
                    SeniorNodeEvent(NodeMessage.Success);//[HelpDoc]
                    return;
                default:
                    break;
            }
        }
    }
}